--- Introduction of the 'http://en.wikipedia.org/wiki/Semigroupoid semigroupoid'.

protected package frege.control.Semigroupoid
        inline (F.•) 
    where

import frege.prelude.PreludeBase 

--- serves only to name 'F.•' in the inline clause
private type F = (->)

infixr 16 `•`  -- f . g . h = f . (g . h)

{--
    Formally, a semigroupoid consists of 
    - a set of things called objects.
    - for every two objects A and B a set Mor(A,B) of things called morphisms from A to B. 
      If @f@ is in Mor(A,B), we write @f : A → B@.
    - for every three objects A, B and C a binary operation 
      @Mor(A,B) × Mor(B,C) → Mor(A,C)@ called *composition* of morphisms. 
      The composition of @f : A → B@ and @g : B → C@ is written as @g • f@.
    
    such that the following axiom holds:
    
    [associativity] if @f : A → B@, @g : B → C@ and @h : C → D@ then @h • (g • f) = (h • g) • f@.
--} 
class Semigroupoid f where
  --- morphism composition
  (.) :: f b c -> f a b -> f a c


infixr 1 `>>>`
infixr 1 `<<<`

--- Right-to-left composition. This is the same a ordinary composition with '•'.
(<<<) :: Semigroupoid f => f b c -> f a b -> f a c
(<<<) = (.)

--- Left-to-right composition
(>>>) :: Semigroupoid f => f a b -> f b c -> f a c
f >>> g = g . f

--- The semigroupoid of Frege values where morphisms are functions.
instance Semigroupoid (->) where
    --- function composition
    f . g = \a -> f (g a)
  